/*
 * @Author: 肖思汗 
 * @Date: 2025-08-13 14:47:48 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2025-08-29 20:40:31
 */

import Taro, { Canvas } from "@tarojs/taro";
import fabric, { Circle as fabricCircle, Path as fabricPath, Polygon as fabricPolygon, Rect as fabricRact } from "fabric";
import { clamp } from "lodash";
import utils from "src/utils/utils";
import FabricCanvas from "../myFabric/FabricCanvas";
import FabricImg from "../myFabric/FabricImg";
import imgCache from "../myFabric/imgCache";
import Transition from "../myFabric/Transition";
import cropBContorls from "./cropBContorls";
import cropBlContorls from "./cropBlContorls";
import cropBrContorls from "./cropBrContorls";
import cropLContorls from "./cropLContorls";
import cropModelStore from "./cropModelStore";
import cropRContorls from "./cropRContorls";
import cropTContorls from "./cropTContorls";
import cropTlContorls from "./cropTlContorls";
import cropTrContorls from "./cropTrContorls";
import FabricMarkRect from "./FabricMarkRect";
import cornerPNG from "./img/corner.png";
import sidePNG from "./img/side.png";


// 裁剪编辑器
class CropEditor extends FabricCanvas {

    constructor() {
        super();
    }

    centeredScaling = false;

    async init(canvas: Canvas) {
        super.init(canvas);

        const contorlWidth = 40;
        // 创建控制器图标
        const createControlIcon = (control, iconPath, angle = 0) => {
            const image = this.canvas.createImage();
            image.src = iconPath;
            image.onload = () => {
                const img = new FabricImg(image, {});
                const { width, height } = image;
                const maxSide = Math.max(width, height);
                img.set({
                    scaleX: contorlWidth / maxSide,
                    scaleY: contorlWidth / maxSide,
                    angle: angle,
                });
                control.icon = img;
                this.requestRenderAll();
            };
        };

        // 为角落控制器使用 corner.svg
        createControlIcon(cropBrContorls, cornerPNG, 270);
        createControlIcon(cropTlContorls, cornerPNG, 90);
        createControlIcon(cropTrContorls, cornerPNG, 180);
        createControlIcon(cropBlContorls, cornerPNG, 0);

        // 为边缘中间控制器使用 side.svg
        createControlIcon(cropTContorls, sidePNG, 270);
        createControlIcon(cropBContorls, sidePNG, 90);
        createControlIcon(cropLContorls, sidePNG, 180);
        createControlIcon(cropRContorls, sidePNG, 0);

        this.add(this.cropRect)
        this.setActiveObject(this.cropRect);

    }

    // 专注显示裁剪框
    focusCropRect() {

        this.resetImageTransition();

        if (this.image) {
            //计算 image 和 cropRect 的位置差值
            const imageOffsetX = this.image.left - this.cropRect.left;
            const imageOffsetY = this.image.top - this.cropRect.top;

            const scale = Math.min((this.width * 0.8) / this.cropRect.getScaledWidth(), (this.height * 0.8) / this.cropRect.getScaledHeight());

            this.imageTransition.set({
                cropScaleX: this.cropRect.scaleX * scale,
                cropScaleY: this.cropRect.scaleY * scale,
            });

            const cropLeft = (this.width - (this.cropRect.getScaledWidth() * scale)) / 2;
            const cropTop = (this.height - (this.cropRect.getScaledHeight() * scale)) / 2;

            this.imageTransition.set({
                cropLeft: cropLeft,
                cropTop: cropTop,
            });

            this.imageTransition.set({
                imageScaleX: this.image.scaleX * scale,
                imageScaleY: this.image.scaleY * scale,
                imageLeft: cropLeft + (imageOffsetX * scale),
                imageTop: cropTop + (imageOffsetY * scale),
            });

        }

        this.requestRenderAll();
    }


    // 设置裁剪区域大小
    setSize(width: number, height: number) {
        this.width = width;
        this.height = height;
        this.canvas.width = width;
        this.canvas.height = height;
        this.renderAll();
    }

    // 设置要裁剪的图片对象
    async setImage({
        url,
        cropX,
        cropY,
        width,
        height,
        clipPath
    }: {
        url: string;
        cropX: number;
        cropY: number;
        width: number;
        height: number;
        clipPath?: fabric.Path;
    }) {

        // const src = "https://static.uniqtee.com/img/1080_883_365443_1d5450fd43b72cb2a43f9dbae904da98.png";

        const image = await this.createImage(url);
        const img = new FabricImg(image, {});
        img.set({
            // src: utils.ossSuffix(url, 1024),
            // 绘制模式设置为 绘制到底层
            globalCompositeOperation: 'destination-over'
        });
        img.setControlsVisibility({
            tl: false,
            tr: false,
            bl: false,
            br: false,
            mt: false,
            mr: false,
            mb: false,
            ml: false,
            mtr: false,
        });

        this.image = img;

        const Xscale = this.width * 0.8 / this.image.width;
        const Yscale = this.height * 0.8 / this.image.height;
        const scale = Math.min(Xscale, Yscale);

        this.image.set({
            scaleX: scale,
            scaleY: scale,
            originX: "left",
            originY: "top",
        });

        this.image.set({
            left: this.width / 2 - this.image.getScaledWidth() / 2,
            top: this.height / 2 - this.image.getScaledHeight() / 2,
        });

        this.cropRect.set({
            left: this.image.left + cropX * this.image.scaleX,
            top: this.image.top + cropY * this.image.scaleY,
            scaleX: width / this.image.width * this.image.scaleX,
            scaleY: height / this.image.height * this.image.scaleY,
            width: this.image.width,
            height: this.image.height,
        });

        if (clipPath) {
            const minScale = Math.min(this.cropRect.width! / clipPath.width!, this.cropRect.height! / clipPath.height!);
            clipPath.left = minScale * clipPath.width! / -2;
            clipPath.top = minScale * clipPath.height! / -2;
            clipPath.scaleX = minScale;
            clipPath.scaleY = minScale;
            if (["path", "Path"].includes(clipPath.type)) {
                this.cropRect.clipPath = new fabricPath("").set(clipPath);
            } else if (["polygon", "Polygon"].includes(clipPath.type)) {
                this.cropRect.clipPath = new fabricPolygon().set(clipPath);
            } else if (["circle", "Circle"].includes(clipPath.type)) {
                this.cropRect.clipPath = new fabricCircle().set(clipPath);
            } else if (["rect", "Rect"].includes(clipPath.type)) {
                this.cropRect.clipPath = new fabricRact().set(clipPath);
            }
            if (this.cropRect.clipPath) {
                this.cropRect.clipPath.set({
                    originX: 'center',
                    originY: 'center',
                });
            }
        } else {
            this.cropRect.clipPath = undefined;
        }
        this.cropRect.set({
            dirty: true
        });
        this.focusCropRect();
        this.requestRenderAll();
    }

    image?: FabricImg;

    // 限制裁剪的大小和范围
    clampCrop() {

        if (this.image) {
            this.image.setCoords();
            this.cropRect.setCoords();

            const { zoom } = cropModelStore;

            // 限制框的X缩放和位置
            if (this.cropRect.scaleX <= this.image.scaleX) {
                this.cropRect.set({
                    scaleX: Math.min(this.cropRect.scaleX, this.image.scaleX),
                });
            } else {
                this.cropRect.set({
                    scaleX: this.image.scaleX,
                });
            }

            //保持比例并限制比例
            if (zoom) {
                this.cropRect.set({
                    scaleY: this.cropRect.getScaledWidth() / (zoom * this.cropRect.height)
                });
            }

            this.image.set({
                left: clamp(
                    this.image.left,
                    this.cropRect.left - (this.image.getScaledWidth() - this.cropRect.getScaledWidth()),
                    this.cropRect.left
                ),
            });

            // 限制框的Y缩放和位置
            if (this.cropRect.scaleY <= this.image.scaleY) {
                this.cropRect.set({
                    scaleY: Math.min(this.cropRect.scaleY, this.image.scaleY),
                });
            } else {
                this.cropRect.set({
                    scaleY: this.image.scaleY,
                });
            }

            //保持比例
            if (zoom) {
                this.cropRect.set({
                    scaleX: (this.cropRect.getScaledHeight() * zoom) / (this.cropRect.width)
                });
            }

            this.image.set({
                top: clamp(
                    this.image.top,
                    this.cropRect.top - (this.image.getScaledHeight() - this.cropRect.getScaledHeight()),
                    this.cropRect.top
                ),
            });

        }
    }

    //裁剪框对象
    cropRect: fabric.Rect = (() => {
        //@ts-ignore
        const cropRect: fabric.Rect = new FabricMarkRect({
            left: 0,
            top: 0,
            width: 300,
            height: 200,
            borderColor: '#ffffff',
            originX: "left",
            originY: "top",
            lockMovementX: true,
            lockMovementY: true,
            centeredScaling: false,
            globalCompositeOperation: 'destination-out',
        });

        // 缩放完成后的回调
        cropRect.on('scaling', (e) => {
            const { zoom } = cropModelStore;
            if (zoom) {
                switch (e.transform.action) {
                    case "scale":
                        if (cropRect.getScaledWidth() < cropRect.getScaledHeight() * zoom) {
                            cropRect.scaleY = cropRect.getScaledWidth() / (zoom * cropRect.height);
                        } else if (cropRect.getScaledHeight() < cropRect.getScaledWidth() * zoom) {
                            cropRect.scaleX = (cropRect.getScaledHeight() * zoom) / cropRect.width;
                        }
                        break;
                    case "scaleX":
                        cropRect.scaleY = cropRect.getScaledWidth() / (zoom * cropRect.height);
                        break;
                    case "scaleY":
                        cropRect.scaleX = (cropRect.getScaledHeight() * zoom) / cropRect.width;
                        break;
                }
            }

            this.clampCrop();
        });


        // 移动和缩放结束
        cropRect.on("modified", () => {
            this.focusCropRect();
        })

        // this.add(cropRect);
        // this.setActiveObject(cropRect);
        this.renderAll();
        return cropRect;
    })();

    // 设置裁剪比例
    setCropZoom(zoom?: number) {
        if (this.image) {
            if (zoom) {

                let originZoom = this.cropRect.getScaledWidth() / this.cropRect.getScaledHeight();

                if (zoom <= originZoom) {
                    this.cropRect.set({
                        scaleY: this.cropRect.scaleY * (originZoom / zoom),
                    });
                } else {
                    this.cropRect.set({
                        scaleX: this.cropRect.scaleX * (zoom / originZoom),
                    });
                }

                this.cropRect.set({
                    left: (this.width - this.cropRect.getScaledWidth()) / 2,
                    top: (this.height - this.cropRect.getScaledHeight()) / 2,
                });
                this.clampCrop();
                this.renderAll();

            } else {
                this.reset();
            }
        }

        this.focusCropRect();
    }

    imgMap = new Map();

    // 创建图片
    async createImage(src) {
        while (!this.canvas) {
            await new Promise(resolve => setTimeout(resolve, 30));
        }

        // 有就直接返回
        if (this.imgMap.has(src)) {
            return this.imgMap.get(src);
        }

        Taro.showLoading({ title: '图片加载中' });

        // 创建图片实例
        const image = this.canvas.createImage();
        await new Promise<void>(async (resolve) => {
            image.onload = () => {
                this.imgMap.set(src, image);
                resolve();
            }
            image.onerror = () => {
                console.warn(`图片加载失败:${src}`);
                Taro.showModal({ title: '图片加载失败' });
                resolve();
            }
            const newSrc = await imgCache.get(utils.ossSuffix(src, 1024));
            image.src = newSrc;
        });
        Taro.hideLoading();
        return image;
    }


    // 重置动画控制器
    resetImageTransition() {
        if (this.image) {
            this.imageTransition.reset({
                cropScaleX: this.cropRect.scaleX,
                cropScaleY: this.cropRect.scaleY,
                cropLeft: this.cropRect.left,
                cropTop: this.cropRect.top,
                imageScaleX: this.image.scaleX,
                imageScaleY: this.image.scaleY,
                imageLeft: this.image.left,
                imageTop: this.image.top,
            })
        }
    }

    // 动画控制对象
    imageTransition = (() => {
        const imageTransition = new Transition({
            cropScaleX: 1,
            cropScaleY: 1,
            cropLeft: 0,
            cropTop: 0,

            imageScaleX: 1,
            imageScaleY: 1,
            imageLeft: 0,
            imageTop: 0,
        });
        imageTransition.setDuration(150);
        imageTransition.onChange(({
            cropScaleX,
            cropScaleY,
            cropLeft,
            cropTop,

            imageScaleX,
            imageScaleY,
            imageLeft,
            imageTop,
        }) => {
            this.cropRect.set({
                scaleX: cropScaleX,
                scaleY: cropScaleY,
                left: cropLeft,
                top: cropTop,
            });
            if (this.image) {
                this.image.set({
                    scaleX: imageScaleX,
                    scaleY: imageScaleY,
                    left: imageLeft,
                    top: imageTop,
                });
            }
            this.requestRenderAll();
        });
        return imageTransition;
    })();

    // 重置
    reset() {
        if (this.image) {

            const Xscale = this.width * 0.8 / this.image.width;
            const Yscale = this.height * 0.8 / this.image.height;
            const scale = Math.min(Xscale, Yscale);

            this.image.set({
                scaleX: scale,
                scaleY: scale,
                originX: "left",
                originY: "top",
            });

            this.image.set({
                left: this.width / 2 - this.image.getScaledWidth() / 2,
                top: this.height / 2 - this.image.getScaledHeight() / 2,
            });

            this.cropRect.set({
                left: this.image.left,
                top: this.image.top,
                scaleX: this.image.scaleX,
                scaleY: this.image.scaleY,
                width: this.image.width,
                height: this.image.height,
            });

            this.requestRenderAll();
        }
    }

    //渲染
    renderAll(ctx = this.ctx) {
        if (!ctx) {
            return;
        }
        ctx.imageSmoothingEnabled = true;

        this.dispatchEvent({
            type: 'before:render',
            ctx
        });

        ctx.save();
        ctx.transform(1, 0, 0, 1, 0, 0);
        ctx.clearRect(0, 0, this.width, this.height);


        // 3. 在整个canvas上绘制半透明黑色
        ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
        ctx.fillRect(0, 0, this.width, this.height);
        ctx.restore();

        // 先绘制裁剪框
        this.cropRect.setCoords();
        this.cropRect.render(ctx);
        this.cropRect._renderControls(ctx);

        // 再绘制图片
        if (this.image) {
            // 绘制到最下面
            this.image.render(ctx);
        }

        this.dispatchEvent({
            type: 'after:render',
            ctx
        });
    }


}


const cropEditor = new CropEditor();

export default cropEditor;

